/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <journal/views/types.h>
#include <baja/common.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

namespace journal { namespace view { namespace winrt {

inline Windows::Storage::StorageFolder^ defaultFolderToStorageFolder(const default_folder defaultFolder)
{
    if (defaultFolder == default_folder::pictures)
    {
        return Windows::Storage::KnownFolders::PicturesLibrary;
    }
    else if (defaultFolder == default_folder::app)
    {
        return Windows::Storage::ApplicationData::Current->LocalFolder;
    }
    else if (defaultFolder == default_folder::documents)
    {
        return Windows::Storage::KnownFolders::DocumentsLibrary;
    }
    else
    {
        BAJA_THROW(std::invalid_argument("defaultFolder"));
        return nullptr;
    }
}

inline std::wstring generateLocalFullFileName(const std::wstring& fileName)
{
    std::wstring targetFolder(Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data());

    std::wostringstream outs;
    outs << targetFolder;
    outs << L"\\";
    outs << fileName;

    return std::wstring(outs.str());
}

inline std::wstring generateUniqueFileName(const std::wstring& prefix, const std::wstring& extension)
{
    boost::uuids::uuid id = boost::uuids::random_generator()();

    std::wostringstream outs;
    outs << prefix;
    outs << L"_";
    outs << id;
    outs << L".";
    outs << extension;

    return std::wstring(outs.str());
}

inline void saveImageAsync(
    const b::wchar* filename,
    const std::shared_ptr<imemory_blob>& blob,
    const default_folder defaultFolder,
    std::function<void(std::shared_ptr<imemory_blob>)> f
    )
{
    String^ name = ref new String(filename);

    struct async_context
    {
        std::function<void(std::shared_ptr<imemory_blob>)> f;
    };

    std::shared_ptr<async_context> context = std::make_shared<async_context>();
    context->f = f;

    // First get the bytes off of the texture
    std::vector<unsigned char> bytes;
    bytes.resize(blob->count());
    std::memcpy(bytes.data(), blob->bytes(), blob->count());

    Windows::Storage::StorageFolder^ folder = winrt::defaultFolderToStorageFolder(defaultFolder);

    concurrency::task<Windows::Storage::StorageFile^> sf = concurrency::task<Windows::Storage::StorageFile^>(
        folder->CreateFileAsync(name, Windows::Storage::CreationCollisionOption::ReplaceExisting));

    sf.then([](Windows::Storage::StorageFile^ storageFile) -> IAsyncOperation<Windows::Storage::Streams::IRandomAccessStream^>^ { 

        return storageFile->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite);

    }).then([bytes, context, blob](Windows::Storage::Streams::IRandomAccessStream^ stream) {

        Platform::Array<unsigned char>^ buffer = ref new Platform::Array<unsigned char>(static_cast<b::uint32>(bytes.size()));
        std::memcpy(buffer->begin(), bytes.data(), bytes.size());

        Windows::Storage::Streams::IOutputStream^ outputStream = stream->GetOutputStreamAt(0);
        Windows::Storage::Streams::DataWriter^ writer = ref new Windows::Storage::Streams::DataWriter(outputStream);

        writer->WriteBytes(buffer);

        c::create_task(writer->StoreAsync()).then(
            [writer, context, blob](c::task<unsigned int> t)
        {
            // delete the writer explicity to free the file handle
            delete writer;
            try
            {
                t.get();
            }
            catch(AccessDeniedException^)
            {
                // TRACK: 164
            }

            if (context->f) context->f(blob);
        });
    });
}

}}} // namespace journal::view::winrt
